import { ISA } from '@/atmosphere'
import { getEntity } from '../base'
import { getFlightPerformanceTable, type FlightPerformanceTable } from './flight-performance'
import type { AircraftType } from './types'

export interface ClimbDescentProfileItem {
  alt: number
  dist: number
  time: number
}

export interface ClimbDescentProfileItemEx extends ClimbDescentProfileItem {
  deltaAlt: number
  deltaDist: number
  duration: number
  rocd: number
  speed: number
  avgRocd: number
  avgSpeed: number
}

export interface ClimbDescentProfile {
  id: string
  altStep: number
  data: ClimbDescentProfileItem[]
}
const ALT_STEP = 100
const MAX_ALT = ALT_STEP * 120

const climbProfiles: Record<string, ClimbDescentProfile> = {}
const descentProfiles: Record<string, ClimbDescentProfile> = {}

export function getClimbProfileById(id: string): ClimbDescentProfile | null {
  const acType = getEntity<AircraftType>('AircraftType', id)
  if (!acType) {
    return null
  }
  return getClimbProfile(acType)
}

export function getDescentProfileById(id: string): ClimbDescentProfile | null {
  const acType = getEntity<AircraftType>('AircraftType', id)
  if (!acType) {
    return null
  }
  return getDescentProfile(acType)
}

export function getClimbProfile(type: AircraftType): ClimbDescentProfile {
  let ret = climbProfiles[type.id]
  if (!ret) {
    ret = makeClimbProfile(type)
    if (ret) {
      climbProfiles[type.id] = ret
    }
  }
  return ret
}

export function getDescentProfile(type: AircraftType): ClimbDescentProfile {
  let ret = descentProfiles[type.id]
  if (!ret) {
    ret = makeDescentProfile(type)
    if (ret) {
      descentProfiles[type.id] = ret
    }
  }
  return ret
}

function makeClimbProfile(type: AircraftType): ClimbDescentProfile {
  const fpTable = getFlightPerformanceTable(type)
  return {
    id: type.id,
    altStep: ALT_STEP,
    data: makeClimbProfileItemList(fpTable)
  }
}

function makeClimbProfileItemList(table: FlightPerformanceTable): ClimbDescentProfileItem[] {
  let preAlt = 0
  let preT = 0
  let preDist = 0
  let alt = 0
  let t = 0
  let dist = 0
  const ret: ClimbDescentProfileItem[] = []
  ret.push({
    alt: 0,
    dist: 0,
    time: 0
  })
  let targetAlt = 100
  while (alt < MAX_ALT) {
    const p = table.getPerformance(alt)
    t++
    if (p.normClimbRate < 0.15) {
      break
    }
    alt += p.normClimbRate
    const tas = ISA.CAS2TAS(alt, p.normClimbIAS)
    dist += tas
    while (targetAlt <= alt) {
      const f = (targetAlt - preAlt) / (alt - preAlt)
      ret.push({
        alt: targetAlt,
        dist: f * (dist - preDist) + preDist,
        time: Math.floor(f * (t - preT) + preT)
      })
      targetAlt += 100
    }
    preAlt = alt
    preDist = dist
    preT = t
  }

  return ret
}

function makeDescentProfile(type: AircraftType): ClimbDescentProfile {
  const fpTable = getFlightPerformanceTable(type)
  return {
    id: type.id,
    altStep: ALT_STEP,
    data: makeDescentProfileItemList(fpTable)
  }
}

function makeDescentProfileItemList(table: FlightPerformanceTable): ClimbDescentProfileItem[] {
  let preAlt = MAX_ALT
  let preT = 0
  let preDist = 0
  let alt = MAX_ALT
  let t = 0
  let dist = 0
  const ret: ClimbDescentProfileItem[] = []
  ret.push({
    alt: MAX_ALT,
    dist: 0,
    time: 0
  })
  let targetAlt = MAX_ALT - 100
  while (alt >= 0 && targetAlt >= 0) {
    const p = table.getPerformance(alt)
    t++
    alt -= p.normDescentRate
    const tas = ISA.CAS2TAS(alt, p.normDescentIAS)
    dist += tas
    while (targetAlt >= alt) {
      const f = (targetAlt - preAlt) / (alt - preAlt)
      ret.push({
        alt: targetAlt,
        dist: f * (dist - preDist) + preDist,
        time: Math.floor(f * (t - preT) + preT)
      })
      targetAlt -= 100
    }
    preAlt = alt
    preDist = dist
    preT = t
  }
  return ret
}
